package com.hmall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.hmall.feign.common.ItemFeignClient;
import com.hmall.domain.constant.EsConstant;
import com.hmall.domain.doc.ItemDoc;
import com.hmall.domain.dto.ItemSearchDto;
import com.hmall.domain.dto.PageDTO;
import com.hmall.domain.pojo.Item;
import com.hmall.search.service.ItemSearchService;
import com.hmall.search.utils.AggFiltersUtil;
import com.hmall.search.utils.SearchByConditions;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 商品es业务层接口实现类
 *
 * @Author XiaoJiangShi
 * @Date 2022/8/10 16:30
 * @Blog blog.XiaoJiangShi.net/996.mba
 * @Description:
 */
@Slf4j
@Service
public class ItemSearchServiceImpl implements ItemSearchService {

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private ItemFeignClient itemFeignClient;

    /**
     * 创建索引
     */
    @Override
    public void creatIndex() {
        //创建索引
        try {
            CreateIndexRequest request = new CreateIndexRequest(EsConstant.ITEM_INDEX);
            request.source(EsConstant.ITEM_INDEX_MAPPING, XContentType.JSON);
            client.indices().create(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导入数据
     */
    @Override
    public void importData() {
        try {
            //导入数据
            BulkRequest bulkRequest = new BulkRequest();
            int page = 1;
            while (true) {
                PageDTO<Item> pageDTO = itemFeignClient.list(page, 500);
                List<Item> list = pageDTO.getList();
                if (list.size() <= 0) {
                    break;
                }
                for (Item item : list) {
                    ItemDoc itemDoc = new ItemDoc(item);
                    bulkRequest.add(new IndexRequest(EsConstant.ITEM_INDEX)
                            .id(itemDoc.getId().toString())
                            .source(JSON.toJSONString(itemDoc), XContentType.JSON));
                }
                client.bulk(bulkRequest, RequestOptions.DEFAULT);
                page++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据搜索框输入，自动补全
     *
     * @param prefix 需补全的数据
     * @return suggestion
     */
    @Override
    public List<String> suggestionByKey(String prefix) {
        List<String> resultList = new ArrayList<>();
        try {
            //获取request对象
            SearchRequest request = new SearchRequest(EsConstant.ITEM_INDEX);
            //填充dcl
            request.source().suggest(new SuggestBuilder().addSuggestion(
                    "item_suggest", new CompletionSuggestionBuilder("suggestion")
                            .prefix(prefix).skipDuplicates(true).size(10)));
            //发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //处理结果
            //获得结果
            CompletionSuggestion completionSuggestion = response.getSuggest().getSuggestion("item_suggest");
            //获取option集合
            List<CompletionSuggestion.Entry.Option> options = completionSuggestion.getOptions();
            //遍历option集合
            for (CompletionSuggestion.Entry.Option option : options) {
                //取出补全结果
                String s = option.getText().toString();
                //添加到集合中
                resultList.add(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultList;
    }

    /**
     * 根据条件搜索并聚合数据
     *
     * @param searchDto 搜索的条件
     * @return 聚合数据
     */
    @Override
    public Map<String, List<String>> polyForCondition(ItemSearchDto searchDto) {
        Map<String, List<String>> map = new HashMap<>(15);
        try {
            SearchRequest request = new SearchRequest(EsConstant.ITEM_INDEX);
            //原始查询
            SearchByConditions.search(request, searchDto);
            //聚合
            AggFiltersUtil.getByAggName(request, "brandAgg", "brand", 15);
            AggFiltersUtil.getByAggName(request, "categoryAgg", "category", 15);

            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            List<String> brandAgg = AggFiltersUtil.getResultByAggName(response, "brandAgg");
            map.put("brandAgg", brandAgg);

            List<String> categoryAgg = AggFiltersUtil.getResultByAggName(response, "categoryAgg");
            map.put("categoryAgg", categoryAgg);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 对商品进行多条件查询
     *
     * @param searchDto 条件对象
     * @return 返回值
     */
    @Override
    public PageDTO<ItemDoc> listByCondition(ItemSearchDto searchDto) {
        PageDTO<ItemDoc> result = new PageDTO<>();
        try {
            SearchRequest request = new SearchRequest(EsConstant.ITEM_INDEX);

            Integer page = searchDto.getPage();
            Integer size = searchDto.getSize();

            SearchByConditions.search(request, searchDto);

            request.source().from((page - 1) * size).size(size);

            String sortBy = searchDto.getSortBy();
            if ("sold".equals(sortBy)){
                request.source().sort(sortBy, SortOrder.DESC);
            }else if ("price".equals(sortBy)){
                request.source().sort(sortBy,SortOrder.ASC);
            }

            request.source().highlighter(new HighlightBuilder().field("name").field("brand").requireFieldMatch(false));

            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            result = SearchByConditions.result(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }


}

